<?php
require_once("Listener.php");
require_once("Wrapper.php");
require_once("Controller.php");

/**
 * Abstract class all servlet components extend.
 */
abstract class Component {
	/**
	 * Property that must be set by children of class.
	 * 
	 * @var array
	 */
	protected $tblAttributes =  array();
	
	/**
	 * Triggers a call to getAttribute whenever a call to get property is is made.
	 * 
	 * @param string $strKey
	 * @return mixed
	 */
	public function __get($strKey) {
		return $this->getAttribute($strKey);
	}
	
	/**
	 * Triggers a call to setAttribute whenever a call to set property is made.
	 * 
	 * @param string $strKey
	 * @param mixed $mixValue
	 * @return void
	 */
	public function __set($strKey, $mixValue) {
		$this->setAttribute($strKey, $mixValue);
	}
	
	/**
	 * Gets attribute by name.
	 * 
	 * @param string $strKey
	 * @return mixed
	 */
	public function getAttribute($strKey) {
		return (isset($this->tblAttributes[$strKey])?$this->tblAttributes[$strKey]:null);
	}	
	
	/**
	 * Sets attribute by name & value.
	 * 
	 * @param string $strKey
	 * @param mixed $mixValue
	 * @throws ServletException
	 */
	public function setAttribute($strKey, $mixValue) {
		if(!$this->isValidKey($strKey)) throw new ServletException("Attributes names must only contain letters & underscores!");
		$this->tblAttributes[$strKey] = $mixValue;
	}
	
	/**
	 * Deletes attribute by name.
	 * 
	 * @param string $strKey
	 * @return void
	 */
	public function removeAttribute($strKey) {
		unset($this->tblAttributes[$strKey]);
	}
	
	/**
	 * Checks if attribute exists.
	 * 
	 * @param string $strKey
	 * @return boolean
	 */
	public function isAttribute($strKey) {
		return isset($this->tblAttributes[$strKey]);
	}
	
	/**
	 * Checks if key obeys naming convention (must only cotain alphabetic letters and underscores)
	 * @param string $strKey
	 * @return boolean
	 */
	public function isValidKey($strKey) {
		if(!preg_match("/^([a-z\_]+)$/is",$strKey)) return false;
		return true;
	}
	
	/**
	 * Outputs attributes as array.
	 * 
	 * @return array
	 */
	public function toArray() {
		return $this->tblAttributes;
	}
	
	/**
	 * Locates and instances a wrapper for the file type supplied. May be user-defined as well as generic.
	 * 
	 * @param	string $strFileType
	 * @return	Wrapper
	 * @throws	ServletException
	 */
	public static function runWrapper($strFileType) {
		$strWrapperClass = ucwords($strFileType)."Wrapper";
		$strWrapperLocation = "";
		if(defined("WRAPPERS_PATH") && file_exists(WRAPPERS_PATH.'/'.$strWrapperClass.'.php')) {
			$strWrapperLocation = WRAPPERS_PATH.'/'.$strWrapperClass.'.php';
		} else {
			$strWrapperLocation = substr(dirname(__FILE__),0,-10)."Response/Wrappers/".$strWrapperClass.".php";
			if(!file_exists($strWrapperLocation)) throw new ServletException("Wrapper file not found: ".$strWrapperLocation);
		}
		
		// get output as string
		require_once($strWrapperLocation);
		if(!class_exists($strWrapperClass)) throw new ServletException("Wrapper class not defined: ".$strWrapperClass);
		$objWrapper = new $strWrapperClass();
		return $objWrapper;
	}
	
	/**
	 * Locates and instances a user-defined listener depending on component name.
	 * 
	 * @param string $strComponentName
	 * @return Listener
	 * @throws ServletException
	 */
	public static function runListener($strComponentName) {
		if(!defined("LISTENERS_PATH")) return;
		
		// gets class name
		$strClass = ucwords($strComponentName)."Listener";
		
		// loads file
		$strFile = LISTENERS_PATH."/".$strClass.".php";
		if(!file_exists($strFile)) return;
		require_once($strFile);
		
		// instances class
		if(!class_exists($strClass)) throw new ServletException("Listener class not found: ".$strClass);
		$objListener = new $strClass();
		return $objListener;
	}
	
	/**
	 * Locates and instances a user-defined controller depending on page requested by client.
	 * 
	 * @return Controller
	 * @throws ServletException
	 */
	public static function runController() {
		if(!defined("CONTROLLERS_PATH")) throw new ServletException("CONTROLLERS_PATH not defined!");
	
		// gets page url
		$strURL = Servlet::$request->page->getURLPage();
		$strCustomInformation = "pages.".substr(str_replace("/","_",strtolower($strURL)),1).".controller";
		if(Servlet::$configuration->isAttribute($strCustomInformation)) {
			$strURL = Servlet::$configuration->getAttribute($strCustomInformation);
		}
	
		// gets class name
		$strClass = str_replace(" ","",ucwords(str_replace("/"," ",strtolower($strURL))))."Controller";
	
		// loads file
		$strFile = CONTROLLERS_PATH."/pages/".$strClass.".php";
		if(!file_exists($strFile)) throw new ServletException("Controller not found on disk: ".$strFile);
		require_once($strFile);
	
		// instances class
		if(!class_exists($strClass)) throw new ServletException("Controller class not found: ".$strClass);
		$objController = new $strClass();
		return $objController;
	}
}